home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / video / xevil-1.000 / xevil-1 / actual.C next >
C/C++ Source or Header  |  1995-08-13  |  45KB  |  2,582 lines

  1. // "actual.C"
  2. // Actual objects to be instantiated.
  3.  
  4. /*    Copyright (C) 1994  Steve Hardt
  5.  
  6.     This program is free software; you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License as published by
  8.     the Free Software Foundation; either version 1, or (at your option)
  9.     any later version.
  10.  
  11.     This program is distributed in the hope that it will be useful,
  12.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.     GNU General Public License for more details.
  15.  
  16.     You should have received a copy of the GNU General Public License
  17.     along with this program; if not, write to the Free Software
  18.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  
  20.     Steve Hardt 
  21.     hardts@athena.mit.edu hardts@media.mit.edu
  22.     hardts@r4002.3dem.bioch.bcm.tmc.edu
  23.     2043 McClendon
  24.     Houston, TX 77030
  25. */
  26.  
  27. #ifndef NO_PRAGMAS
  28. #pragma implementation "actual.h"
  29. #endif
  30.  
  31.  
  32. // Include Files
  33. #include <strstream.h>
  34.  
  35. #include "utils.h"
  36. #include "coord.h"
  37. #include "world.h"
  38. #include "physical.h"
  39. #include "actual.h"
  40.  
  41. // Bitmap files.  Also contain constants and some simple methods.
  42. #include "bitmaps/explosion/explosion.bitmaps"
  43. #include "bitmaps/fire/fire.bitmaps"
  44. #include "bitmaps/n_protection/n_protection.bitmaps"
  45. #include "bitmaps/t_protection/t_protection.bitmaps"
  46.  
  47. #include "bitmaps/shell/shell.bitmaps"
  48. #include "bitmaps/swap_shell/swap_shell.bitmaps"
  49. #include "bitmaps/lance/lance.bitmaps"
  50. #include "bitmaps/frog_shell/frog_shell.bitmaps"
  51. #include "bitmaps/fireball/fireball.bitmaps"
  52. #include "bitmaps/missile/missile.bitmaps"
  53. #include "bitmaps/star/star.bitmaps"
  54.  
  55. #include "bitmaps/trapdoor/trapdoor.bitmaps"
  56. #include "bitmaps/home/home.bitmaps"
  57. #include "bitmaps/grenade/grenade.bitmaps"
  58. #include "bitmaps/xit/xit.bitmaps"
  59. #include "bitmaps/flag/flag.bitmaps"
  60.  
  61. #include "bitmaps/rock/rock.bitmaps"
  62. #include "bitmaps/weight/weight.bitmaps"
  63. #include "bitmaps/altar_of_sin/altar_of_sin.bitmaps"
  64. #include "bitmaps/doppel/doppel.bitmaps"
  65. #include "bitmaps/transmogifier/transmogifier.bitmaps"
  66. #include "bitmaps/med_kit/med_kit.bitmaps"
  67. #include "bitmaps/n_shield/n_shield.bitmaps"
  68. #include "bitmaps/t_shield/t_shield.bitmaps"
  69. #include "bitmaps/bomb/bomb.bitmaps"
  70.  
  71. #include "bitmaps/chainsaw/chainsaw.bitmaps"
  72. #include "bitmaps/pistol/pistol.bitmaps"
  73. #include "bitmaps/m_gun/m_gun.bitmaps"
  74. #include "bitmaps/lancer/lancer.bitmaps"
  75. #include "bitmaps/f_thrower/f_thrower.bitmaps"
  76. #include "bitmaps/launcher/launcher.bitmaps"
  77. #include "bitmaps/grenades/grenades.bitmaps"
  78. #include "bitmaps/shotgun/shotgun.bitmaps"
  79. #include "bitmaps/stars/stars.bitmaps"
  80. #include "bitmaps/swapper/swapper.bitmaps"
  81. #include "bitmaps/frog_gun/frog_gun.bitmaps"
  82.  
  83. #include "bitmaps/enforcer/enforcer.bitmaps"
  84. #include "bitmaps/frog/frog.bitmaps"
  85. #include "bitmaps/hero/hero.bitmaps"
  86. #include "bitmaps/ninja/ninja.bitmaps"
  87. #include "bitmaps/alien/alien.bitmaps"
  88. #include "bitmaps/chopper_boy/chopper_boy.bitmaps"
  89. #include "bitmaps/lemming/lemming.bitmaps"
  90. #include "bitmaps/fire_demon/fire_demon.bitmaps"
  91.  
  92.  
  93.  
  94. Explosion::Explosion(WorldP w,LocatorP l,const Pos &mid,
  95.              const Id &bomb_er,int r,int dMax)
  96.      : Physical(context,w,l) 
  97.   bomber = bomb_er;
  98.   Pos pos;
  99.   pos.x = mid.x - EXPLOSION_VISIBLE_RADIUS;
  100.   pos.y = mid.y - EXPLOSION_VISIBLE_RADIUS;
  101.  
  102.   Size size;
  103.   size.width = size.height = 2 * EXPLOSION_VISIBLE_RADIUS;
  104.  
  105.   Area narea(AR_RECT,pos,size);
  106.   area = narea;
  107.   middle = mid;
  108.   radius = r;
  109.   damageMax = dMax;
  110. }
  111.  
  112.  
  113.  
  114. Boolean Explosion::collidable()
  115. {
  116.   return False;
  117. }
  118.  
  119.  
  120.  
  121. const Area &Explosion::get_area()
  122. {
  123.   return area;
  124. }
  125.  
  126.  
  127.  
  128. const Area &Explosion::get_area_next()
  129. {
  130.   return area;
  131. }
  132.  
  133.  
  134.  
  135. void Explosion::draw(Drawable buffer,Xvars &xvars,int dpyNum,
  136.              const Area &bufArea)
  137. {
  138.   Pos pos;
  139.   Size size;
  140.   area.get_rect(pos,size);
  141.   Size offset = area - bufArea;
  142.  
  143.   XFillArc(xvars.dpy[dpyNum],buffer,xvars.gc[dpyNum],
  144.        offset.width,offset.height,
  145.        size.width,size.height,
  146.        0,23040);
  147. /*  XFillRectangle(xvars.dpy,buffer,xvars.gc,
  148.          offset.width,offset.height,
  149.          size.width,size.height); */
  150. }
  151.  
  152.  
  153.  
  154. void Explosion::act() 
  155. {
  156.   PhysicalP nearby[OL_NEARBY_MAX];
  157.   int nitems;
  158.   LocatorP locator = get_locator();
  159.   locator->get_nearby(nearby,nitems,this,radius);
  160.   
  161.   PhysicalP p = locator->lookup(bomber);
  162.   int hit = 0;
  163.   
  164.   for (int n = 0; n < nitems; n++)
  165.     if (nearby[n]->collidable())
  166.       { 
  167.     const Area &otherArea = nearby[n]->get_area();
  168.     int distance = middle.distance(otherArea.get_middle());
  169.     assert (distance >= 0);
  170.     nearby[n]->corporeal_attack(p,damageMax*(radius-distance)/radius);
  171.     hit++;
  172.       }
  173.  
  174.   ostrstream msg;
  175.   msg << "Explosion hits " << hit << " objects." << ends;
  176.   locator->message_enq(msg.str());
  177.  
  178.   kill_self();
  179.   Physical::act();
  180. }
  181.  
  182.  
  183.  
  184. Fire::Fire(WorldP w,LocatorP l,const Pos &mid,Boolean coll)
  185. : Physical(context,w,l)
  186. {
  187.   Pos pos;
  188.   pos.x = mid.x - FIRE_DIAMETER_INIT / 2;
  189.   pos.y = mid.y - FIRE_DIAMETER_INIT / 2;
  190.   Size size;
  191.   size.width = size.height = FIRE_DIAMETER_INIT;
  192.  
  193.   Area nArea(AR_RECT,pos,size);
  194.   area = areaNext = nArea;
  195.   isCollidable = coll;
  196. }
  197.  
  198.  
  199.  
  200. int Fire::get_damage() 
  201. {
  202.   return FIRE_DAMAGE;
  203. }
  204.  
  205.  
  206.  
  207. const Area &Fire::get_area()
  208. {
  209.   return area;
  210. }
  211.  
  212.  
  213.  
  214. const Area &Fire::get_area_next()
  215. {
  216.   return areaNext;
  217. }
  218.  
  219.  
  220.  
  221. Boolean Fire::collidable()
  222. {
  223.   return isCollidable;
  224. }
  225.  
  226.  
  227.  
  228. void Fire::draw(Drawable buffer,Xvars &xvars,int dpyNum,const Area &bufArea)
  229. {
  230.   const Area &area = get_area();
  231.   Pos pos;
  232.   Size size;
  233.   area.get_rect(pos,size);
  234.   Size offset = area - bufArea;
  235.  
  236.   XSetForeground(xvars.dpy[dpyNum],xvars.gc[dpyNum],xvars.red[dpyNum]);
  237.   XFillArc(xvars.dpy[dpyNum],buffer,xvars.gc[dpyNum],
  238.        offset.width,offset.height,
  239.        size.width,size.height,
  240.        0,23040);
  241.   XSetForeground(xvars.dpy[dpyNum],xvars.gc[dpyNum],xvars.black[dpyNum]);
  242. }
  243.  
  244.  
  245.  
  246. void Fire::avoid(PhysicalP)
  247. {}
  248.  
  249.  
  250.  
  251. void Fire::collide(PhysicalP other)
  252. {
  253.   if (other->is_shot())
  254.     return;
  255.   other->heat_attack(NULL,FIRE_HEAT,True);
  256. }
  257.  
  258.  
  259.  
  260. void Fire::corporeal_attack(PhysicalP,int)
  261. {}
  262.  
  263.  
  264.  
  265. void Fire::heat_attack(PhysicalP,int,Boolean)
  266. {}
  267.  
  268.  
  269.  
  270. void Fire::act()
  271. {
  272.   Pos pos;
  273.   Size size;
  274.   area.get_rect(pos,size);
  275.   
  276.   size.width -= (FIRE_RADIUS_DELTA * 2);
  277.   size.height = size.width;
  278.   if (size.width <= 0)
  279.     kill_self();
  280.   else
  281.     {
  282.       pos.x += FIRE_RADIUS_DELTA;
  283.       pos.y += FIRE_VEL_Y;
  284.       Area nArea(AR_RECT,pos,size);
  285.       areaNext = nArea;
  286.     }
  287.   Physical::act();
  288. }
  289.  
  290.  
  291.  
  292. void Fire::update()
  293. {
  294.   area = areaNext;
  295.   Physical::update();
  296. }
  297.  
  298.  
  299.  
  300. NProtection::NProtection(WorldP w,LocatorP l,const Area &area)
  301.   : Protection(context,xdata,w,l,area)
  302. {
  303.   n = N_PROTECTION_N;
  304. }
  305.  
  306.  
  307.  
  308. Boolean NProtection::corporeal_protect(int)
  309. {
  310.   assert(n >= 0);
  311.   if (n == 0)
  312.     return False;
  313.   n--;
  314.   if (n == 0 )
  315.     kill_self();
  316.   return True;
  317. }
  318.  
  319.  
  320.  
  321. Boolean NProtection::heat_protect(int,Boolean)
  322. {
  323.   assert(n >= 0);
  324.   return False;
  325. }
  326.  
  327.  
  328.  
  329. TProtection::TProtection(WorldP w,LocatorP l,const Area &area)
  330.   : Protection(context,xdata,w,l,area)
  331. {
  332.   timer.set(T_PROTECTION_TIME);
  333. }
  334.  
  335.  
  336.  
  337. void TProtection::act()
  338. {
  339.   if (timer.ready())
  340.     kill_self();
  341.   timer.clock();
  342.  
  343.   Protection::act();
  344. }
  345.  
  346.  
  347.  
  348. Boolean TProtection::corporeal_protect(int)
  349. {
  350.   return True;
  351. }
  352.  
  353.  
  354.  
  355. Boolean TProtection::heat_protect(int,Boolean)
  356. {
  357.   return True;
  358. }
  359.  
  360.  
  361.  
  362. Rock::Rock(WorldP w,LocatorP l,const Pos &pos) 
  363.      : Heavy(context,xdata,w,l,pos) 
  364. {}
  365.  
  366.  
  367.  
  368. Weight::Weight(WorldP w,LocatorP l,const Pos &pos) 
  369.      : Heavy(context,xdata,w,l,pos) 
  370. {}
  371.  
  372.  
  373.  
  374. AltarOfSin::AltarOfSin(WorldP w,LocatorP l,const Pos &pos)
  375.      : Heavy(context,xdata,w,l,pos)  
  376. {
  377.   turnTaken = False;
  378. }
  379.  
  380.  
  381.  
  382. void AltarOfSin::corporeal_attack(PhysicalP other,int)
  383. {
  384.   /* Don't fuck with the Altar of Sin. */
  385.  
  386.   if (!turnTaken)
  387.     {
  388.       IntelP intel;
  389.       if (other && (other->get_class_id() != A_AltarOfSin) &&
  390.       (intel = other->get_intel()))
  391.     {
  392.       LocatorP locator = get_locator();
  393.       ostrstream str;
  394.       
  395.       if (Utils::coinFlip() && other->is_moving())  
  396.         /* Turned into a frog. */
  397.         { 
  398.           str << intel->get_name() << " attacks the Altar of Sin and is "
  399.         << "turned into a frog." << ends;
  400.           locator->message_enq(str.str());
  401.           
  402.           other->set_intel(NULL);
  403.           if (!other->get_mapped())
  404.         cerr << "Warning:AltarOfSin::corporeal_attack: object "
  405.           << "should be mapped." << endl;
  406.           other->set_mapped_next(False);
  407.           
  408.           const Area &area = other->get_area();
  409.           Pos pos = area.get_middle() - 0.5 * Frog::get_size_max();
  410.           
  411.           PhysicalP frog = new Frog(get_world(),locator,pos,other->get_id());
  412.           assert(frog);
  413.           frog->set_intel(intel);
  414.           locator->add(frog);
  415.         }
  416.       else
  417.         /* Lose all health. */
  418.         {
  419.           str << "BLASPHMER!  " << intel->get_name() << 
  420.         " loses health for daring to attack the Altar of Sin." << ends;
  421.           locator->message_enq(str.str());
  422.           
  423.           int damage = other->get_health();
  424.           other->corporeal_attack(this,damage);
  425.         }
  426.     }
  427.       turnTaken = True;
  428.     }
  429. }
  430.  
  431.  
  432.  
  433. void AltarOfSin::heat_attack(PhysicalP,int,Boolean)
  434. {}
  435.  
  436.  
  437.  
  438. void AltarOfSin::collide(PhysicalP other)
  439. {
  440.   IntelP intel;
  441.   if ((intel = other->get_intel()) && intel->is_human() && !turnTaken)
  442.     {
  443.       int lives = intel->get_lives();
  444.       LocatorP locator = get_locator();
  445.       ostrstream msg;
  446.  
  447.       // If human has infinite lives, give him some points(kills) instead.
  448.       if (lives == IT_INFINITE_LIVES)
  449.     {
  450.       for (int n = 0; n < ALTAR_OF_SIN_KILLS; n++)
  451.         intel->add_human_kill();
  452.       
  453.       msg << intel->get_name() << " sells soul for " 
  454.         << ALTAR_OF_SIN_KILLS << " kills." << ends;
  455.     }
  456.       else
  457.     {
  458.       intel->set_lives(lives + 1);
  459.       msg << intel->get_name() << " sells soul for an extra life." << ends;
  460.     }
  461.  
  462.       locator->message_enq(msg.str());
  463.       kill_self();
  464.       turnTaken = True;
  465.     }
  466.   else
  467.     Heavy::collide(other);
  468. }
  469.  
  470.  
  471.  
  472. void AltarOfSin::update()
  473. {
  474.   turnTaken = False;
  475.   Heavy::update();
  476. }
  477.  
  478.  
  479.  
  480. Doppel::Doppel(WorldP w,LocatorP l,const Pos &pos)
  481. : Item(context,xdata,w,l,pos)
  482. {}
  483.  
  484.  
  485.  
  486. void Doppel::use(PhysicalP p)
  487. {
  488.   assert(p && p->get_intel());
  489.   stats.add_use();
  490.   WorldP world = get_world();
  491.   LocatorP locator = get_locator();
  492.   
  493.   PhysicalP obj = create_physical(p->get_area(),p->get_class_id());
  494.  
  495.   IntelOptions ops;
  496.   ops.psychotic = True;
  497.   ops.classFriends = False;
  498.   ops.ignoreItems = True;
  499.   ops.ignoreLemmings = True;
  500.   NeutralP neutral = 
  501.     new Neutral(world,locator,"Slave",&ops,
  502.         ITpsychotic|ITclassFriends|ITignoreItems|ITignoreLemmings,
  503.         p->get_intel());
  504.   assert(neutral);
  505.   locator->register_neutral(neutral);
  506.  
  507.   locator->add(obj);
  508.   obj->set_intel(neutral);
  509. //  obj->set_dont_collide(p);
  510.   
  511.   kill_self();
  512.   Item::use(p);
  513. }
  514.  
  515.  
  516.  
  517. PhysicalP Doppel::create_physical(const Area &area,ClassId classId)
  518. {
  519.   WorldP world = get_world();
  520.   LocatorP locator = get_locator();
  521.   PhysicalP obj;
  522.   Pos middle = area.get_middle();
  523.   
  524.   switch (classId)
  525.     {
  526.     case A_Ninja:
  527.       obj = new Ninja(world,locator,middle - 0.5 * Ninja::get_size_max());
  528.       break;
  529.     case A_Hero:
  530.       obj = new Hero(world,locator,middle - 0.5 * Hero::get_size_max());
  531.       break;
  532.     case A_ChopperBoy:
  533.       obj = new ChopperBoy(world,locator,
  534.                middle - 0.5 * ChopperBoy::get_size_max());
  535.       break;
  536.     case A_Alien:
  537.       obj = new Alien(world,locator,middle - 0.5 * Alien::get_size_max());
  538.       break;
  539.     default:
  540.       // choose randomly
  541.       switch (Utils::choose(4)) {
  542.       case 0: return create_physical(area,A_Ninja);
  543.       case 1: return create_physical(area,A_Hero);
  544.       case 2: return create_physical(area,A_ChopperBoy);
  545.       case 3: return create_physical(area,A_Alien);
  546.       };
  547.     };
  548.  
  549.   assert(obj);
  550.   return obj;
  551. }
  552.  
  553.  
  554.  
  555. Stats Doppel::stats;
  556.  
  557.  
  558.  
  559. Transmogifier::Transmogifier(WorldP w,LocatorP l,const Pos &pos)
  560. : AutoUse(context,xdata,w,l,pos)
  561. {}
  562.  
  563.  
  564.  
  565. void Transmogifier::use(PhysicalP other)
  566. {
  567.   assert(other->alive());
  568.   stats.add_use();
  569.  
  570.   IntelP intel = other->get_intel();
  571.  
  572.   // Must check that other does not have protection against swapping.
  573.   if (intel && !other->swap_protect())
  574.     {
  575.       LocatorP locator = get_locator();
  576.       const Area &area = other->get_area();
  577.       PhysicalP p = new_physical(area.get_middle());
  578.       locator->add(p);
  579.  
  580.       p->set_intel(intel);
  581.       other->set_intel(NULL);
  582.       other->set_quiet_death();
  583.       other->kill_self();
  584.     }
  585.   kill_self();
  586.   AutoUse::use(other);
  587. }
  588.  
  589.  
  590.  
  591. PhysicalP Transmogifier::new_physical(const Pos &middle)
  592. {
  593.   PhysicalP obj;
  594.   LocatorP locator = get_locator();
  595.   WorldP world = get_world();
  596.   
  597.   // Either a Frog, Hero, Ninja, ChopperBoy, or Alien.
  598.   switch (Utils::choose(5)) {
  599.   case 0:
  600.     {
  601.       Id invalid;
  602.       Pos pos = middle - 0.5 * Frog::get_size_max();
  603.       obj = new Frog(world,locator,pos,invalid);
  604.     }
  605.     break;
  606.   case 1:
  607.     {
  608.       Pos pos = middle - 0.5 * Hero::get_size_max();
  609.       obj = new Hero(world,locator,pos);
  610.     }
  611.     break;
  612.   case 2:
  613.     {
  614.       Pos pos = middle - 0.5 * Ninja::get_size_max();
  615.       obj = new Ninja(world,locator,pos);
  616.     }
  617.     break;
  618.   case 3:
  619.     {
  620.       Pos pos = middle - 0.5 * ChopperBoy::get_size_max();
  621.       obj = new ChopperBoy(world,locator,pos);
  622.     }
  623.     break;
  624.   case 4:
  625.     {
  626.       Pos pos = middle - 0.5 * Alien::get_size_max();
  627.       obj = new Alien(world,locator,pos);
  628.     }
  629.     break;
  630.   default:
  631.     assert(0);
  632.   };
  633.  
  634.   assert(obj);
  635.   return obj;
  636. }
  637.  
  638.  
  639.  
  640. Stats Transmogifier::stats;
  641.  
  642.  
  643.  
  644. MedKit::MedKit(WorldP w,LocatorP l,const Pos &pos) 
  645.      : AutoUse(context,xdata,w,l,pos) 
  646. {}
  647.  
  648.  
  649.  
  650. void MedKit::use(PhysicalP p)
  651. {
  652.   stats.add_use();
  653.   assert(p->alive());
  654.   p->heal();
  655.   kill_self();
  656.   AutoUse::use(p);
  657. }
  658.  
  659.  
  660.  
  661. Stats MedKit::stats;
  662.  
  663.  
  664.  
  665. NShield::NShield(WorldP w,LocatorP l,const Pos &pos) 
  666.      : Shield(context,xdata,w,l,pos) 
  667. {}
  668.  
  669.  
  670.  
  671. ProtectionP NShield::create_protection(const Area &area)
  672. {
  673.   ProtectionP pr = new NProtection(get_world(),get_locator(),area);
  674.   assert(pr);
  675.   return pr;
  676. }
  677.  
  678.  
  679.  
  680. TShield::TShield(WorldP w,LocatorP l,const Pos &pos) 
  681.      : Shield(context,xdata,w,l,pos) 
  682. {}
  683.  
  684.  
  685.  
  686. ProtectionP TShield::create_protection(const Area &area)
  687. {
  688.   ProtectionP pr = new TProtection(get_world(),get_locator(),area);
  689.   assert(pr);
  690.   return pr;
  691. }
  692.  
  693.  
  694.  
  695. Bomb::Bomb(WorldP w,LocatorP l,const Pos &p) :
  696.        Animated(context,xdata,w,l,p) 
  697. {
  698.   set_frame(BOMB_FRAME_INACTIVE);
  699.   set_frame_next(BOMB_FRAME_INACTIVE);
  700.   frame = BOMB_FRAME_INACTIVE;
  701.  
  702.   Timer ntimer(BOMB_TIME); 
  703.   timer = ntimer;
  704.   active = False;
  705.   defused = False;
  706. }
  707.  
  708.  
  709.  
  710. Boolean Bomb::is_bomb()
  711. {
  712.   return True;
  713. }
  714.  
  715.  
  716.  
  717. void Bomb::use(PhysicalP bomberP)
  718. {
  719.   if (!active) 
  720.     {
  721.       frame = BOMB_FRAME_ACTIVE;
  722.       timer.set();
  723.       active = True;
  724.       if (bomberP)
  725.     bomber = bomberP->get_id();
  726.       LocatorP locator = get_locator();
  727.       ostrstream msg;
  728.       msg << frame << ends;
  729.       locator->message_enq(msg.str());
  730.  
  731.       set_cant_take();
  732.     }
  733.   Animated::use(bomberP);
  734. }
  735.  
  736.  
  737.  
  738. void Bomb::act()
  739. {
  740.   if (active)
  741.     timer.clock();
  742.   
  743.   if (active && timer.ready())
  744.     {
  745.       if (! frame)
  746.     kill_self();
  747.       else
  748.     {
  749.       timer.set();
  750.       frame--;
  751.       
  752.       LocatorP locator = get_locator();
  753.       ostrstream msg;
  754.       msg << frame << ends;
  755.       locator->message_enq(msg.str());
  756.     }
  757.     }
  758.   
  759.   set_frame_next(frame);
  760.  
  761.  Animated::act();
  762. }
  763.  
  764.  
  765.  
  766. void Bomb::set_quiet_death()
  767. {
  768.   defused = True;
  769.   Animated::set_quiet_death();
  770. }
  771.  
  772.  
  773.  
  774. void Bomb::die()
  775. {
  776.   if (!defused)
  777.     {
  778.       stats.add_use();
  779.  
  780.       WorldP world = get_world();
  781.       LocatorP locator = get_locator();
  782.       const Area area = get_area();
  783.       
  784.       PhysicalP explosion = 
  785.     new Explosion(world,locator,area.get_middle(),bomber,
  786.               BOMB_EXPLOSION_RADIUS,BOMB_EXPLOSION_DAMAGE_MAX);
  787.       assert (explosion);
  788.       locator->add(explosion);
  789.     }  
  790.  
  791.   Animated::die();
  792. }
  793.  
  794.  
  795.  
  796. Stats Bomb::stats;
  797.  
  798.  
  799.  
  800. Shell::Shell(WorldP w,LocatorP l,const Pos &p,const Id &shooter,
  801.          Dir d) 
  802.      : Shot(context,xdata,w,l,p,shooter,d) 
  803. {}
  804.  
  805.  
  806.  
  807. SwapShell::SwapShell(WorldP w,LocatorP l,const Pos &p,
  808.              const Id &sh, const Id &sw,Dir d)
  809.      : Shot(context,xdata,w,l,p,sh,d)
  810. {
  811.   swapper = sw;
  812. }
  813.  
  814.  
  815.  
  816. void SwapShell::collide(PhysicalP other)
  817. {
  818.   if (other->is_shot())
  819.     return;
  820.  
  821.   LocatorP locator = get_locator();
  822.   const Id &shooter = get_shooter();
  823.   PhysicalP shooterP;
  824.  
  825.   // Do nothing if shooter no longer exists.
  826.   if (!other->swap_protect() && 
  827.       (shooterP = locator->lookup(shooter)))
  828.     { 
  829.       // Swap souls.
  830.       IntelP tmp = other->get_intel();
  831.       /* Don't swap unless both shooter and other have intelligence. */
  832.       if (tmp && shooterP->get_intel()) 
  833.     {
  834.       other->set_intel(shooterP->get_intel());
  835.       shooterP->set_intel(tmp);
  836.       
  837.       // Destroy swapper.
  838.       PhysicalP swapperP;
  839.       if (locator->lookup(swapperP,swapper) == OL_NO_SIG)
  840.         swapperP->kill_self();
  841.     }
  842.     }
  843.  
  844.   kill_self();
  845. }
  846.  
  847.  
  848.  
  849. Lance::Lance(WorldP w,LocatorP l,const Pos &p,const Id &shooter,Dir d)
  850.        : Shot(context,xdata,w,l,p,shooter,d,d) 
  851. {}
  852.  
  853.  
  854.  
  855. FrogShell::FrogShell(WorldP w,LocatorP l,const Pos &p,
  856.              const Id &shooter,const Id &frog_gun,Dir d) 
  857.      : Shot(context,xdata,w,l,p,shooter,d) 
  858. {
  859.   frogGun = frog_gun;
  860. }
  861.  
  862.  
  863.  
  864. void FrogShell::collide(PhysicalP other)
  865. {
  866.   // Be careful not to frog a Frog.
  867.   if (other->is_shot() || other->get_class_id() == A_Frog)
  868.     return;
  869.  
  870.   IntelP intel = other->get_intel();
  871.   if (!other->frog_protect() && intel && other->is_moving())
  872.     {
  873.       other->set_intel(NULL);
  874.       assert(other->get_mapped());
  875.       other->set_mapped_next(False);
  876.       
  877.       const Area &area = other->get_area();
  878.       Pos pos = area.get_middle() - 0.5 * Frog::get_size_max();
  879.  
  880.       LocatorP locator = get_locator();
  881.       PhysicalP frog = new Frog(get_world(),locator,pos,other->get_id());
  882.       assert(frog);
  883.       frog->set_intel(intel);
  884.       locator->add(frog);
  885.  
  886.       // Destroy frogGun.
  887.       PhysicalP p;
  888.       if (p = locator->lookup(frogGun))
  889.     p->kill_self();
  890.     }
  891.  
  892.   kill_self();
  893. }
  894.  
  895.  
  896.  
  897. Fireball::Fireball(WorldP w,LocatorP l,const Pos &p,const Id &shooter,
  898.            Dir d,int h,int t) 
  899.      : Shot(context,xdata,w,l,p,shooter,d) 
  900. {
  901.   if (t == -1)
  902.     timer.set(FIREBALL_TIME);
  903.   else
  904.     timer.set(t);
  905.  
  906.   if (h == -1)
  907.     heat = FIREBALL_HEAT;
  908.   else
  909.     heat = h;
  910. }
  911.  
  912.  
  913.  
  914. void Fireball::collide(PhysicalP other)
  915. {
  916.   // Fireballs are not destroyed by shots.
  917.   if (other->is_shot() && other->get_class_id() != A_Missile)
  918.     return;
  919.  
  920.   LocatorP locator = get_locator();
  921.   const Id &shooter = get_shooter();
  922.   PhysicalP p = locator->lookup(shooter);
  923.  
  924.   if (p)
  925.     {
  926.       // Special case.  Fireballs fired by FireDemons hurt other FireDemons.
  927.       if (p->get_class_id() == A_FireDemon && 
  928.       other->get_class_id() == A_FireDemon)
  929.     {
  930.       other->corporeal_attack(p,FIREBALL_FIRE_DEMON_DAMAGE);
  931.       kill_self();
  932.     }
  933.       else
  934.     other->heat_attack(p,heat);
  935.     }
  936.   else
  937.     other->heat_attack(NULL,heat);
  938. }
  939.  
  940.  
  941.  
  942. void Fireball::act()
  943. {
  944.   if (timer.ready())
  945.     kill_self();
  946.  
  947.   timer.clock();
  948.   Shot::act();
  949. }
  950.  
  951.  
  952.  
  953. void Fireball::draw(Drawable buffer,Xvars &xvars,int dpyNum,const Area &bufArea)
  954. {
  955.   const Area &area = get_area();
  956.   Pos pos;
  957.   Size size;
  958.   area.get_rect(pos,size);
  959.   Size offset = area - bufArea;
  960.  
  961.   XSetForeground(xvars.dpy[dpyNum],xvars.gc[dpyNum],xvars.red[dpyNum]);
  962.   XFillArc(xvars.dpy[dpyNum],buffer,xvars.gc[dpyNum],
  963.        offset.width,offset.height,
  964.        size.width,size.height,
  965.        0,23040);
  966.   XSetForeground(xvars.dpy[dpyNum],xvars.gc[dpyNum],xvars.black[dpyNum]);
  967. }
  968.  
  969.  
  970.  
  971. Missile::Missile(WorldP w,LocatorP l,const Pos &p,const Id &sh,Dir d)
  972. : Shot(context,xdata,w,l,p,sh,d,d) 
  973. {
  974.   timer.set(MISSILE_DESTRUCT_TIME);
  975.   Timer nTimer(MISSILE_ROTATE_TIME);
  976.   rotate = nTimer;
  977.   hasTarget = False;
  978.   shooterId = sh;
  979. }
  980.  
  981.  
  982.  
  983. void Missile::act()
  984. {
  985.   LocatorP locator = get_locator();
  986.  
  987.   // Find a target.
  988.   if (!hasTarget)
  989.     {
  990.       PhysicalP nearby[OL_NEARBY_MAX];
  991.       int nearbyNum;
  992.       // Should work even though this not fully constructed.
  993.       locator->get_nearby(nearby,nearbyNum,this,MISSILE_RADIUS);
  994.       
  995.       // Search through list for best possible candidate.
  996.       const Area &area = get_area();
  997.       Pos middle = area.get_middle();
  998.       int distance_2 = -1;  // Best so far.
  999.       
  1000.       for (int n = 0; n < nearbyNum; n++)
  1001.     if (nearby[n]->alive() &&
  1002.         nearby[n]->is_creature() &&
  1003.         nearby[n]->get_id() != shooterId)
  1004.       {
  1005.         const Area &area = nearby[n]->get_area();
  1006.         int dist_2 = middle.distance_2(area.get_middle());
  1007.         
  1008.         if (distance_2 == -1 || dist_2 < distance_2)
  1009.           {
  1010.         targetId = nearby[n]->get_id();
  1011.         distance_2 = dist_2;
  1012.         hasTarget = True;
  1013.           }
  1014.       }
  1015.     }
  1016.  
  1017.   if (rotate.ready())
  1018.     {
  1019.       rotate.set();
  1020.       
  1021.       PhysicalP target;
  1022.       if (locator->lookup(target,targetId) == OL_NO_SIG)
  1023.     {
  1024.       Boolean noChange = False;
  1025.       Dir dir = get_dir();
  1026.       const Area &area = get_area();
  1027.       const Area &targetArea = target->get_area();
  1028.       Dir dirTo = area.dir_to(targetArea);
  1029.       if (dir > dirTo)
  1030.         {
  1031.           if (dir - dirTo > (CO_DIR_PURE / 2))
  1032.         dir++;
  1033.           else
  1034.         dir--;
  1035.         }
  1036.       else if (dirTo > dir)
  1037.         {
  1038.           if (dirTo - dir > (CO_DIR_PURE / 2))
  1039.         dir--;
  1040.           else
  1041.         dir++;
  1042.         }
  1043.       else 
  1044.         noChange = True;
  1045.       
  1046.       if (!noChange)
  1047.         {
  1048.           if (dir >= CO_DIR_MAX)
  1049.         dir -= CO_DIR_PURE;
  1050.           if (dir < (CO_DIR_MAX - CO_DIR_PURE))
  1051.         dir += CO_DIR_PURE;
  1052.           
  1053.           set_dir_next(dir);
  1054.           const Vel *unitVels = get_unit_vels();
  1055.           set_vel_next(context.speed * unitVels[dir]);
  1056.         }
  1057.     }
  1058.     }
  1059.   
  1060.   if (timer.ready())
  1061.     kill_self();
  1062.   
  1063.   timer.clock();
  1064.   rotate.clock();
  1065.   Shot::act();
  1066. }
  1067.  
  1068.  
  1069.  
  1070. Star::Star(WorldP w,LocatorP l,const Pos &p,const Id &sh,Dir d)
  1071. : Shot(context,xdata,w,l,p,sh,d) 
  1072. {}
  1073.  
  1074.  
  1075.  
  1076. Trapdoor::Trapdoor(WorldP w,LocatorP l,const Pos &pos,const Id &home_id)
  1077. : Moving(context,xdata,w,l,pos)
  1078. {
  1079.   Timer nTimer(TRAPDOOR_TIME);
  1080.   timer = nTimer;
  1081.   timer.set();
  1082.   
  1083.   lemmingsNum = 0;
  1084.   homeId = home_id;
  1085. }
  1086.  
  1087.  
  1088.  
  1089. Boolean Trapdoor::collidable()
  1090. {
  1091.   return False;
  1092. }
  1093.  
  1094.  
  1095.  
  1096. int Trapdoor::get_drawing_level()
  1097. {
  1098.   return 0;
  1099. }
  1100.  
  1101.  
  1102.  
  1103. void Trapdoor::act()
  1104. {
  1105.   if (timer.ready() && lemmingsNum < LEMMINGS_MAX)
  1106.     {
  1107.       LocatorP l = get_locator();
  1108.       WorldP w = get_world();
  1109.       const Area &area = get_area();
  1110.       Pos pos = area.get_middle();
  1111.       Size lemmingSize = Lemming::get_size_max();
  1112.       pos.x -= lemmingSize.width / 2;
  1113.       pos.y += lemmingSize.height;
  1114.       PhysicalP lemming = new Lemming(w,l,pos);
  1115.       assert(lemming);
  1116.  
  1117.       char lemmingStr[20];
  1118.       ostrstream str(lemmingStr,20);
  1119.       str << "lemming-" << lemmingsNum << ends;
  1120.       NeutralP lemmingIntel = new LemmingIntel(w,l,lemmingStr,homeId);
  1121.       lemming->set_intel(lemmingIntel);
  1122.       l->register_neutral(lemmingIntel);
  1123.       lemmings[lemmingsNum] = lemmingIntel->get_intel_id();
  1124.  
  1125.       l->add(lemming);
  1126.       
  1127.       lemmingsNum++;
  1128.       timer.set();
  1129.     }
  1130.  
  1131.   timer.clock();
  1132.   Moving::act();
  1133. }
  1134.  
  1135.  
  1136.  
  1137. Home::Home(WorldP w,LocatorP l,const Pos &pos)
  1138. : Moving(context,xdata,w,l,pos)
  1139. {
  1140.   lemmingsSafe = 0;
  1141. }
  1142.  
  1143.  
  1144.  
  1145. Boolean Home::collidable()
  1146. {
  1147.   return False;
  1148. }
  1149.  
  1150.  
  1151.  
  1152. int Home::get_drawing_level()
  1153. {
  1154.   return 0;
  1155. }
  1156.  
  1157.  
  1158.  
  1159. void Home::act()
  1160. {
  1161.   PhysicalP nearby[OL_NEARBY_MAX];
  1162.   int nItems;
  1163.   LocatorP locator = get_locator();
  1164.   locator->get_nearby(nearby,nItems,this,HOME_RADIUS);
  1165.  
  1166.   for (int n = 0; n < nItems; n++)
  1167.     {
  1168.       IntelP intel = nearby[n]->get_intel();
  1169.       if (intel && intel->is_lemming_intel())
  1170.     {
  1171.       nearby[n]->set_quiet_death();
  1172.       nearby[n]->kill_self();
  1173.       lemmingsSafe++;
  1174.     }
  1175.     }
  1176.   Moving::act();
  1177. }
  1178.  
  1179.  
  1180.  
  1181. Grenade::Grenade(WorldP w,LocatorP l,const Pos &pos,const Id &sh,
  1182.          Dir dir,Speed speed)
  1183. : Falling(context,xdata,w,l,pos,dir)
  1184. {
  1185.   assert(dir != CO_air);
  1186.   const Vel *unitVels = get_unit_vels();
  1187.   set_vel_next(speed * unitVels[dir]);
  1188.   
  1189.   timer.set(GRENADE_TIME);
  1190.   shooter = sh;
  1191.   defused = False;
  1192. }
  1193.  
  1194.  
  1195.  
  1196. Grenade::Grenade(WorldP w,LocatorP l,const Pos &pos,const Id &sh,
  1197.          const Vel &vel)
  1198. : Falling(context,xdata,w,l,pos,vel.get_dir())
  1199. {
  1200.   stats.add_creation();
  1201.  
  1202.   set_vel_next(vel);
  1203.   timer.set(GRENADE_TIME);
  1204.   shooter = sh;
  1205.   defused = False;
  1206. }
  1207.  
  1208.  
  1209.  
  1210. void Grenade::set_quiet_death()
  1211. {
  1212.   defused = True;
  1213.   Falling::set_quiet_death();
  1214. }
  1215.  
  1216.  
  1217.  
  1218. void Grenade::act()
  1219. {
  1220.   if (timer.ready())
  1221.     kill_self();
  1222.   
  1223.   timer.clock();
  1224.   Falling::act();
  1225. }
  1226.  
  1227.  
  1228.  
  1229. void Grenade::die()
  1230. {
  1231.   if (!defused)
  1232.     {
  1233.       WorldP world = get_world();
  1234.       LocatorP locator = get_locator();
  1235.       const Area area = get_area();
  1236.   
  1237.       PhysicalP explosion = 
  1238.     new Explosion(world,locator,area.get_middle(),shooter,
  1239.               GRENADE_EXPLOSION_RADIUS,GRENADE_EXPLOSION_DAMAGE_MAX);
  1240.       assert (explosion);
  1241.       locator->add(explosion);
  1242.     }
  1243.   Falling::die();
  1244. }
  1245.  
  1246.  
  1247.  
  1248. Stats Grenade::stats;
  1249.  
  1250.  
  1251.  
  1252. Xit::Xit(WorldP w,LocatorP l,const Pos &pos) 
  1253. : Touchable(context,xdata,w,l,pos)
  1254. {}
  1255.  
  1256.  
  1257.  
  1258. Flag::Flag(WorldP w,LocatorP l,const Pos &pos) 
  1259. : Touchable(context,xdata,w,l,pos)
  1260. {}
  1261.  
  1262.  
  1263.  
  1264. Chainsaw::Chainsaw(WorldP w,LocatorP l,const Pos &p) 
  1265. : Cutter(context,xdata,w,l,p) 
  1266. {}
  1267.  
  1268.  
  1269.  
  1270. Gun::Gun(const GunContext &g_c,
  1271.      GunXdata &x_data,
  1272.      WorldP w,
  1273.      LocatorP l,
  1274.      const Pos &p) :
  1275.        Weapon(g_c.weaponContext,x_data,w,l,p) 
  1276. {
  1277.   assert(g_c.ammoInitial <= g_c.ammoMax);
  1278.  
  1279.   gc = &g_c;
  1280.   Timer ntimer(g_c.shotTime); 
  1281.   timer = ntimer;
  1282.   ammo = g_c.ammoInitial;
  1283. }
  1284.  
  1285.  
  1286.  
  1287. Boolean Gun::is_gun()
  1288. {
  1289.   return True;
  1290. }
  1291.  
  1292.  
  1293.  
  1294. Boolean Gun::ready()
  1295. {
  1296.   return timer.ready();
  1297. }
  1298.  
  1299.  
  1300.  
  1301. int Gun::get_ammo()
  1302. {
  1303.   return ammo;
  1304. }
  1305.  
  1306.  
  1307.  
  1308. int Gun::get_ammo_max()
  1309. {
  1310.   return gc->ammoMax;
  1311. }
  1312.  
  1313.  
  1314.  
  1315. void Gun::update()
  1316. {
  1317.   timer.clock(); 
  1318.   Weapon::update();
  1319. }
  1320.  
  1321.  
  1322.  
  1323. void Gun::set_ammo(int val)
  1324. {
  1325.   assert(val <= gc->ammoMax && val >= 0);
  1326.   ammo = val;
  1327. }
  1328.  
  1329.  
  1330.  
  1331. Size Gun::get_shot_size(Dir)
  1332. {
  1333.   return Shell::get_size();
  1334. }
  1335.  
  1336.  
  1337.  
  1338. Dir Gun::compute_weapon_dir(ITcommand command)
  1339. {
  1340.   switch (command) {
  1341.   case IT_WEAPON_R:
  1342.     return CO_R;
  1343.   case IT_WEAPON_DN_R:
  1344.     return CO_DN_R;
  1345.   case IT_WEAPON_DN:
  1346.     return CO_DN;
  1347.   case IT_WEAPON_DN_L:
  1348.     return CO_DN_L;
  1349.   case IT_WEAPON_L:
  1350.     return CO_L;
  1351.   case IT_WEAPON_UP_L:
  1352.     return CO_UP_L;
  1353.   case IT_WEAPON_UP:
  1354.     return CO_UP;
  1355.   case IT_WEAPON_UP_R:
  1356.     return CO_UP_R;
  1357.   };
  1358.   return CO_air;
  1359. }
  1360.  
  1361.  
  1362.  
  1363. void Gun::fire(const Id &id,ITcommand command)
  1364. {
  1365.   Dir dir = compute_weapon_dir(command);
  1366.   _fire(id,dir);
  1367. }
  1368.  
  1369.  
  1370.  
  1371. void Gun::_fire(const Id &id,Dir dir,Boolean setTimer,Boolean costsAmmo)
  1372. /* NOTE: PH_AMMO_UNLIMITED is not currently tested. */
  1373. {
  1374.   assert((ammo == PH_AMMO_UNLIMITED) ||
  1375.      ((ammo <= gc->ammoMax) && (ammo >= 0)));
  1376.  
  1377.   // Person who fired weapon may not exist anymore. (See FThrower)
  1378.   LocatorP locator = get_locator();
  1379.   PhysicalP p;
  1380.   if (p = locator->lookup(id))
  1381.     {
  1382.       if ((dir != CO_air) && ready() && 
  1383.       ((ammo == PH_AMMO_UNLIMITED) || (ammo > 0)))
  1384.     {
  1385.       const Area &area = p->get_area();
  1386.       
  1387.       Pos newPos = area.adjacent_rect(get_shot_size(dir),dir);
  1388.       WorldP world = get_world();
  1389.       LocatorP locator = get_locator();
  1390.       
  1391.       PhysicalP shot = create_shot(p,world,locator,newPos,dir);
  1392.       shot->set_dont_collide(p);
  1393.       locator->add(shot);
  1394.       if (setTimer)
  1395.         timer.set();
  1396.       
  1397.       if (costsAmmo && ammo != PH_AMMO_UNLIMITED)
  1398.         ammo--;
  1399.     }
  1400.     }  
  1401. }
  1402.  
  1403.  
  1404.  
  1405. PhysicalP Gun::create_shot(PhysicalP shooter,WorldP world,LocatorP locator,
  1406.                const Pos &pos,Dir dir)
  1407. {
  1408.   PhysicalP shot = new Shell(world,locator,pos,shooter->get_id(),dir);
  1409.   assert (shot);
  1410.   return shot;
  1411. }
  1412.  
  1413.  
  1414.  
  1415. SingleGun::SingleGun(const SingleGunContext &c,
  1416.              SingleGunXdata &x_data,
  1417.              WorldP w,LocatorP l,const Pos &p) 
  1418.     : Gun(c.gunContext,x_data,w,l,p) 
  1419. {}
  1420.  
  1421.  
  1422.  
  1423. Boolean SingleGun::ready()
  1424. {
  1425.   // Can only fire if previous shot has been destroyed.
  1426.   PhysicalP shot;
  1427.   LocatorP locator = get_locator();
  1428.  
  1429.   return (locator->lookup(shot,shotId) == OL_NOT_FOUND) && Gun::ready();
  1430. }
  1431.  
  1432.  
  1433.  
  1434. void SingleGun::fire(const Id &id,ITcommand command)
  1435. {
  1436.   assert(get_ammo() == PH_AMMO_UNLIMITED);
  1437.  
  1438.   LocatorP locator = get_locator();
  1439.   PhysicalP p;
  1440.   if (locator->lookup(p,id) == OL_NO_SIG)
  1441.     {
  1442.       Dir dir = compute_weapon_dir(command);
  1443.       if ((dir != CO_air) && ready())
  1444.     {
  1445.       const Area &area = p->get_area();
  1446.       
  1447.       Pos newPos = area.adjacent_rect(get_shot_size(dir),dir);
  1448.       WorldP world = get_world();
  1449.       
  1450.       LocatorP locator = get_locator();
  1451.       PhysicalP shot = create_shot(p,world,locator,newPos,dir);
  1452.       shot->set_dont_collide(p);
  1453.       locator->add(shot);
  1454.       
  1455.       shotId = shot->get_id();
  1456.     }
  1457.     }
  1458. }
  1459.  
  1460.  
  1461.  
  1462. Pistol::Pistol(WorldP w,LocatorP l,const Pos &p) 
  1463.      : Gun(context,xdata,w,l,p) 
  1464. {}
  1465.  
  1466.  
  1467.  
  1468. MGun::MGun(WorldP w,LocatorP l,const Pos &p) 
  1469.      : Gun(context,xdata,w,l,p) 
  1470. {}
  1471.  
  1472.  
  1473.  
  1474. Swapper::Swapper(WorldP w,LocatorP l,const Pos &p) :
  1475.        SingleGun(context,xdata,w,l,p) 
  1476. {}
  1477.  
  1478.  
  1479.  
  1480. Size Swapper::get_shot_size(Dir)
  1481. {
  1482.   return SwapShell::get_size();
  1483. }
  1484.  
  1485.  
  1486.  
  1487. PhysicalP Swapper::create_shot(PhysicalP shooter,WorldP w,LocatorP l,
  1488.                    const Pos &pos,Dir d)
  1489. {
  1490.   PhysicalP swapShell = new SwapShell(w,l,pos,shooter->get_id(),get_id(),d);
  1491.   assert (swapShell);
  1492.   return swapShell;
  1493. }
  1494.  
  1495.  
  1496.  
  1497. Lancer::Lancer(WorldP w,LocatorP l,const Pos &p) 
  1498.      : Gun(context,xdata,w,l,p) 
  1499. {}
  1500.  
  1501.  
  1502.  
  1503. Size Lancer::get_shot_size(Dir dir)
  1504. {
  1505.   return Lance::get_size(dir);
  1506. }
  1507.  
  1508.  
  1509.  
  1510. Dir Lancer::compute_weapon_dir(ITcommand command)
  1511. {
  1512.   switch (command) {
  1513.   case IT_WEAPON_R:
  1514.     return CO_R;
  1515.   case IT_WEAPON_DN_R:
  1516.     return CO_DN_R_R;
  1517.   case IT_WEAPON_DN:
  1518.     return CO_DN;
  1519.   case IT_WEAPON_DN_L:
  1520.     return CO_DN_L_L;
  1521.   case IT_WEAPON_L:
  1522.     return CO_L;
  1523.   case IT_WEAPON_UP_L:
  1524.     return CO_UP_L_L;
  1525.   case IT_WEAPON_UP:
  1526.     return CO_UP;
  1527.   case IT_WEAPON_UP_R:
  1528.     return CO_UP_R_R;
  1529.   };
  1530.   return CO_air;
  1531. }
  1532.  
  1533.  
  1534.  
  1535. PhysicalP Lancer::create_shot(PhysicalP shooter,WorldP w,LocatorP l,
  1536.                   const Pos &pos,Dir d)
  1537. {
  1538.   PhysicalP lance = new Lance(w,l,pos,shooter->get_id(),d);
  1539.   assert (lance);
  1540.   return lance;
  1541. }
  1542.  
  1543.  
  1544.  
  1545. FrogGun::FrogGun(WorldP w,LocatorP l,const Pos &p) :
  1546.        SingleGun(context,xdata,w,l,p) 
  1547. {}
  1548.  
  1549.  
  1550.  
  1551. Size FrogGun::get_shot_size(Dir)
  1552. {
  1553.   return FrogShell::get_size();
  1554. }
  1555.  
  1556.  
  1557.  
  1558. PhysicalP FrogGun::create_shot(PhysicalP shooter,WorldP w,LocatorP l,
  1559.                    const Pos &pos,Dir d)
  1560. {
  1561.   PhysicalP shot = new FrogShell(w,l,pos,shooter->get_id(),get_id(),d);
  1562.   assert (shot);
  1563.   return shot;
  1564. }
  1565.  
  1566.  
  1567.  
  1568. FThrower::FThrower(WorldP w,LocatorP l,const Pos &p) :
  1569.        Gun(context,xdata,w,l,p) 
  1570. {
  1571.   Timer nTimer(F_THROWER_FIRE_TIME);
  1572.   stopFiring = nTimer;
  1573.   isFiring = False;
  1574. }
  1575.  
  1576.  
  1577.  
  1578. PhysicalP FThrower::create_shot(PhysicalP shooter,WorldP w,LocatorP l,
  1579.                   const Pos &pos,Dir d)
  1580. {
  1581.   PhysicalP fireball = new Fireball(w,l,pos,shooter->get_id(),d);
  1582.   assert (fireball);
  1583.   return fireball;
  1584. }
  1585.  
  1586.  
  1587.  
  1588. void FThrower::fire(const Id &id,ITcommand command)
  1589. {
  1590.   killerId = id;
  1591.   fireCommand = command;
  1592.   stopFiring.set();
  1593.   isFiring = True;
  1594. }
  1595.  
  1596.  
  1597.  
  1598. void FThrower::act()
  1599. {
  1600.   if (isFiring && stopFiring.ready())
  1601.     isFiring = False;
  1602.  
  1603.   if (isFiring)
  1604.     Gun::fire(killerId,fireCommand);
  1605.   
  1606.   stopFiring.clock();
  1607.   Gun::act();
  1608. }
  1609.  
  1610.  
  1611.  
  1612. Size FThrower::get_shot_size(Dir)
  1613. {
  1614.   return Fireball::get_size();
  1615. }
  1616.  
  1617.  
  1618.  
  1619. Launcher::Launcher(WorldP w,LocatorP l,const Pos &p) 
  1620. : Gun(context,xdata,w,l,p) 
  1621. {}
  1622.  
  1623.  
  1624.  
  1625. Size Launcher::get_shot_size(Dir dir)
  1626. {
  1627.   return Missile::get_size(dir);
  1628. }
  1629.  
  1630.  
  1631.  
  1632. PhysicalP Launcher::create_shot(PhysicalP shooter,WorldP world,
  1633.                 LocatorP locator,const Pos &pos,Dir dir)
  1634. {
  1635.   PhysicalP shot = new Missile(world,locator,pos,shooter->get_id(),dir);
  1636.   assert (shot);
  1637.   return shot;
  1638. }
  1639.  
  1640.  
  1641.  
  1642. Grenades::Grenades(WorldP w,LocatorP l,const Pos &p) 
  1643. : Gun(context,xdata,w,l,p) 
  1644. {}
  1645.  
  1646.  
  1647.  
  1648. Size Grenades::get_shot_size(Dir dir)
  1649. {
  1650.   return Grenade::get_size(dir);
  1651. }
  1652.  
  1653.  
  1654.  
  1655. PhysicalP Grenades::create_shot(PhysicalP shooter,WorldP world,
  1656.                 LocatorP locator,const Pos &pos,Dir dir)
  1657. {
  1658.   Speed speed;
  1659.   if (dir == CO_UP_L || dir == CO_UP || dir == CO_UP_R)
  1660.     speed = GRENADES_TOSS_SPEED;
  1661.   else if (dir == CO_R || dir == CO_DN_R || dir == CO_DN_L || dir == CO_L)
  1662.     speed = GRENADES_ROLL_SPEED;
  1663.   else if (dir == CO_DN)
  1664.     speed = 0;
  1665.   else
  1666.     assert(0);
  1667.  
  1668.   assert(shooter->is_moving());
  1669.   const Vel *unitVels = get_unit_vels();
  1670.   Vel vel = ((MovingP)shooter)->get_vel() + speed * unitVels[dir];
  1671.  
  1672. //  PhysicalP shot = new Grenade(world,locator,pos,shooter->get_id(),dir,speed);
  1673.   PhysicalP shot = new Grenade(world,locator,pos,shooter->get_id(),vel);
  1674.   assert (shot);
  1675.   return shot;
  1676. }
  1677.  
  1678.  
  1679.  
  1680. Shotgun::Shotgun(WorldP w,LocatorP l,const Pos &p) 
  1681.      : Gun(context,xdata,w,l,p) 
  1682. {}
  1683.  
  1684.  
  1685.  
  1686. void Shotgun::fire(const Id &id,ITcommand command)
  1687. {
  1688.   Dir dir = compute_weapon_dir(command);
  1689.   LocatorP l = get_locator();
  1690.   PhysicalP shooter;
  1691.   int ammo;
  1692.  
  1693.   if ((shooter = l->lookup(id)) && dir != CO_air && ready() && 
  1694.       (ammo = get_ammo()) > 0)
  1695.     {
  1696.       const Area &shooterArea = shooter->get_area();
  1697.       
  1698.       PhysicalP nearby[OL_NEARBY_MAX];
  1699.       int nearbyNum;
  1700.       l->get_nearby(nearby,nearbyNum,shooter,SHOTGUN_RADIUS);
  1701.       const Vel *unitVels = get_unit_vels();
  1702.  
  1703.       for (int n = 0; n < nearbyNum; n++)
  1704.     {
  1705.       Size diff = nearby[n]->get_area() - shooterArea;
  1706.  
  1707.       if (diff.get_dir() == dir)
  1708.         {
  1709.           if (nearby[n]->is_moving())
  1710.         ((MovingP)nearby[n])->
  1711.           set_extra_vel_next((SHOTGUN_SLAM_MOMENTUM / 
  1712.                       nearby[n]->get_mass()) *
  1713.                      unitVels[dir]);
  1714. //          ((MovingP)nearby[n])->set_vel_next(0);
  1715.           nearby[n]->corporeal_attack(shooter,SHOTGUN_DAMAGE);
  1716.         }
  1717.     }
  1718.  
  1719.       if (shooter->is_moving())
  1720.     ((MovingP)shooter)->
  1721.       set_extra_vel_next((SHOTGUN_RECOIL_MOMENTUM /
  1722.                   shooter->get_mass()) * 
  1723.                  unitVels[Coord::dir_opposite(dir)]);
  1724.       
  1725.       set_ammo(ammo - 1);
  1726.       set_shot_timer();
  1727.     }
  1728. }
  1729.  
  1730.  
  1731.  
  1732. Stars::Stars(WorldP w,LocatorP l,const Pos &p) 
  1733.      : Gun(context,xdata,w,l,p) 
  1734. {}
  1735.  
  1736.  
  1737.  
  1738. Size Stars::get_shot_size(Dir)
  1739. {
  1740.   return Star::get_size();
  1741. }
  1742.  
  1743.  
  1744.  
  1745. PhysicalP Stars::create_shot(PhysicalP shooter,WorldP world,LocatorP locator,
  1746.                  const Pos &pos,Dir dir)
  1747. {
  1748.   PhysicalP shot = new Star(world,locator,pos,shooter->get_id(),dir);
  1749.   assert (shot);
  1750.   return shot;
  1751. }
  1752.  
  1753.  
  1754.  
  1755. void Stars::fire(const Id &shooterId,ITcommand command)
  1756. {
  1757.   LocatorP locator = get_locator();
  1758.   PhysicalP shooter = locator->lookup(shooterId);
  1759.   if (shooter)
  1760.     {
  1761.       // Ninjas firing stars give a wider spread.
  1762.       int delta = (shooter->get_class_id() == A_Ninja) ? 2 : 1;
  1763.  
  1764.       // Fire a spread of shots around center.
  1765.       Dir center = Intel::command_weapon_to_dir_8(command);
  1766.       if (center != CO_air)
  1767.     for (Dir baseDir = center - delta; baseDir <= center + delta; baseDir++)
  1768.       {
  1769.         Dir dir;
  1770.         if (baseDir >= CO_DIR_MAX)
  1771.           dir = baseDir - CO_DIR_PURE;
  1772.         else if (baseDir < CO_DIR_MAX - CO_DIR_PURE)
  1773.           dir = baseDir + CO_DIR_PURE;
  1774.         else
  1775.           dir = baseDir;
  1776.  
  1777.         // Only set the timer on the last shot.
  1778.         Boolean lastOne = (baseDir == center + delta);
  1779.         Gun::_fire(shooterId,dir,lastOne,lastOne);
  1780.       }
  1781.     }
  1782. }
  1783.  
  1784.  
  1785.  
  1786. Enforcer::Enforcer(WorldP w,LocatorP l,const Pos &rawPos)
  1787.      : Creature(creatureContext,creatureXdata,w,l,rawPos),
  1788.        Grounded(groundedContext,groundedXdata),
  1789.        Suicide(suicideContext,suicideXdata)
  1790. {}
  1791.  
  1792.  
  1793.  
  1794. Boolean Enforcer::is_suicide()
  1795. {
  1796.   return True;
  1797. }
  1798.  
  1799.  
  1800.  
  1801. Boolean Enforcer::prickly()
  1802. {
  1803.   return True;
  1804. }
  1805.  
  1806.  
  1807.  
  1808. void Enforcer::collide(PhysicalP other)
  1809. {
  1810.   if (alive())
  1811.     other->corporeal_attack(this,ENFORCER_DAMAGE);
  1812.  
  1813.   Grounded::collide(other);
  1814. }
  1815.  
  1816.  
  1817.  
  1818. void Enforcer::act()
  1819. {
  1820.   Grounded::_act();
  1821.   Suicide::_act();
  1822.   Creature::act();
  1823. }
  1824.  
  1825.  
  1826.  
  1827. void Enforcer::die()
  1828. {
  1829.   if (!get_quiet_death())
  1830.     stats.add_death(get_birth_time());
  1831.   
  1832.   Grounded::die();
  1833. }
  1834.  
  1835.  
  1836. Stats Enforcer::stats;
  1837.  
  1838.  
  1839.  
  1840. Frog::Frog(WorldP w,LocatorP l,const Pos &rawPos,const Id &un_mapped) 
  1841.      : Creature(creatureContext,creatureXdata,w,l,rawPos),
  1842.        Hopping(hoppingContext,hoppingXdata)
  1843. {
  1844.   PhysicalP p;
  1845.   if (l->lookup(p,un_mapped) == OL_NO_SIG)
  1846.     {
  1847.       unmapped = un_mapped;
  1848.       assert (p->get_intel() == NULL);
  1849.  
  1850.       timer.set(FROG_TIME);
  1851.       unmappedSet = True;
  1852.     }
  1853.   else
  1854.     unmappedSet = False;
  1855. }
  1856.  
  1857.  
  1858.  
  1859. void Frog::act()
  1860. {
  1861.   // alive() may not be necessary.
  1862.   if (alive() && unmappedSet)
  1863.     {
  1864.       LocatorP locator = get_locator();
  1865.       PhysicalP p = locator->lookup(unmapped);
  1866.       if (p && p->alive())
  1867.     {
  1868.       assert(p->is_moving());
  1869.       const Area &area = get_area();
  1870.       ((MovingP)p)->set_middle_next(area.get_middle());
  1871.       
  1872.       if (timer.ready())
  1873.         {
  1874.           p->set_intel(get_intel());
  1875.           p->set_mapped_next(True);
  1876.           set_intel(NULL);
  1877.           set_quiet_death();
  1878.           kill_self();
  1879.           
  1880.           unmappedSet = False;
  1881.         }
  1882.     }
  1883.     }
  1884.   
  1885.   if (unmappedSet)
  1886.     timer.clock();
  1887.   Hopping::act();
  1888. }
  1889.  
  1890.  
  1891.  
  1892. void Frog::die()
  1893. {
  1894.   if (!get_quiet_death())
  1895.     stats.add_death(get_birth_time());
  1896.   
  1897.   if (unmappedSet)
  1898.     {
  1899.       LocatorP locator = get_locator();
  1900.       PhysicalP p;
  1901.       if ((p = locator->lookup(unmapped)) && p->alive())
  1902.     {
  1903.       assert(p->get_intel() == NULL);
  1904.       p->set_intel(get_intel());
  1905.       set_intel(NULL);
  1906.  
  1907.       if (get_quiet_death())
  1908.         {
  1909.           p->set_quiet_death();
  1910.         }
  1911.       else
  1912.         {
  1913.           p->set_mapped_next(True);
  1914.           const Area &area = get_area();
  1915.           assert(p->is_moving());
  1916.           ((MovingP)p)->set_middle_next(area.get_middle());
  1917.         }
  1918.  
  1919.       if (!p->die_called())
  1920.         {
  1921.           /* Partial hack to prevent corpse from getting knocked out of
  1922.          the world. */
  1923.           const Area &area = p->get_area_next();
  1924.           WorldP world = get_world();
  1925.           if (!world->inside(area.middle_wsquare()))
  1926.         p->set_quiet_death();
  1927.  
  1928.           p->kill_self();
  1929.           p->die();
  1930.         }
  1931.       
  1932.       set_quiet_death();
  1933.     }
  1934.     }
  1935.   Hopping::die();
  1936. }
  1937.  
  1938.  
  1939.  
  1940. Stats Frog::stats;
  1941.  
  1942.  
  1943.  
  1944. Hero::Hero(WorldP w,LocatorP l,const Pos &rawPos) 
  1945.      : Creature(creatureContext,creatureXdata,w,l,rawPos),
  1946.        Walking(walkingContext,walkingXdata),
  1947.        Fighter(fighterContext,fighterXdata),
  1948.        User(userContext,userXdata)
  1949. {
  1950.   healthMin = get_health();
  1951.   Timer t(HERO_HEAL_TIME);
  1952.   healTimer = t;
  1953.   healTimer.set();
  1954. }
  1955.  
  1956.  
  1957.  
  1958. Boolean Hero::is_fighter() 
  1959. {
  1960.   return True;
  1961. }
  1962.  
  1963.  
  1964.  
  1965. Boolean Hero::is_walking() 
  1966. {
  1967.   return True;
  1968. }
  1969.  
  1970.  
  1971.  
  1972. Boolean Hero::is_user() 
  1973. {
  1974.   return True;
  1975. }
  1976.  
  1977.  
  1978.  
  1979. void Hero::get_pixmap_mask(int dpyNum,Pixmap &pixmap,Pixmap &mask,Dir dir,
  1980.                int animNum)
  1981. {
  1982.   Fighter::get_pixmap_mask(dpyNum,pixmap,mask,dir,animNum);
  1983. }
  1984.  
  1985.  
  1986.  
  1987. void Hero::get_size_offset_next(Size &size,Size &offset,Dir dirNext)
  1988. {
  1989.   Fighter::get_size_offset_next(size,offset,dirNext);
  1990. }
  1991.  
  1992.  
  1993.  
  1994. int Hero::get_weapons_num()
  1995. {
  1996.   return User::get_weapons_num();
  1997. }
  1998.  
  1999.  
  2000.  
  2001. int Hero::get_items_num()
  2002. {
  2003.   return User::get_items_num();
  2004. }
  2005.  
  2006.  
  2007.  
  2008. PhysicalP Hero::get_weapon(int n)
  2009. {
  2010.   return User::get_weapon(n);
  2011. }
  2012.  
  2013.  
  2014.  
  2015. PhysicalP Hero::get_item(int n)
  2016. {
  2017.   return User::get_item(n);
  2018. }
  2019.  
  2020.  
  2021.  
  2022. PhysicalP Hero::get_weapon_current()
  2023. {
  2024.   return User::get_weapon_current();
  2025. }
  2026.  
  2027.  
  2028.  
  2029. PhysicalP Hero::get_item_current()
  2030. {
  2031.   return User::get_item_current();
  2032. }
  2033.  
  2034.  
  2035.  
  2036. void Hero::set_mapped_next(Boolean val)
  2037. {
  2038.  User::set_mapped_next(val);
  2039. }
  2040.  
  2041.  
  2042.  
  2043. void Hero::heal()
  2044. {
  2045.   // Somewhat of a hack.  Skipping a level in calling up the tree. 
  2046.   Creature::heal();
  2047.  
  2048.   healthMin = get_health_max();
  2049. }
  2050.  
  2051.  
  2052.  
  2053. void Hero::act()
  2054. {
  2055.   if (alive())
  2056.     {
  2057.       // Heal Hero up to HERO_HEAL_MULTIPLIER * min health.
  2058.       Health health = get_health();
  2059.       if (health < healthMin)
  2060.     healthMin = health;
  2061.       
  2062.       if (healTimer.ready())
  2063.     {
  2064.       Health healthBest = 
  2065.         min(get_health_max(),((int)(healthMin * HERO_HEAL_MULTIPLIER)));
  2066.       Health healthNext = health + HERO_HEAL;
  2067.       if (healthNext > healthBest)
  2068.         healthNext = healthBest;
  2069.       
  2070.       set_health_next(healthNext);
  2071.       healTimer.set();
  2072.     }
  2073.       healTimer.clock();
  2074.     }
  2075.  
  2076.   Walking::_act();
  2077.   Fighter::_act();
  2078.   Creature::act();
  2079.   User::_act();
  2080.   // NOTE: Creature::act() before User::act();
  2081. }
  2082.  
  2083.  
  2084.  
  2085. void Hero::update()
  2086. {
  2087. //  Walking::_update();
  2088.   Fighter::_update();
  2089. //  User::_update();
  2090.   Creature::update();
  2091. }
  2092.  
  2093.  
  2094.  
  2095. void Hero::die()
  2096. {
  2097.   if (!get_quiet_death())
  2098.     stats.add_death(get_birth_time());
  2099.  
  2100.   // Walking::_die();
  2101.   User::_die();
  2102.   // User::_die();
  2103.   Creature::die();
  2104. }
  2105.  
  2106.  
  2107.  
  2108. void Hero::collide(PhysicalP other) 
  2109. {
  2110.   if (!Fighter::_collide(other) && !User::_collide(other))
  2111.     Creature::collide(other);
  2112. }
  2113.  
  2114.  
  2115.  
  2116. void Hero::init_x(Xvars &xvars)
  2117. {
  2118.   Fighter::init_x(xvars);
  2119. }
  2120.  
  2121.  
  2122.  
  2123. Stats Hero::stats;
  2124.  
  2125.  
  2126.  
  2127. Ninja::Ninja(WorldP w,LocatorP l,const Pos &rawPos) 
  2128.      : Creature(creatureContext,creatureXdata,w,l,rawPos),
  2129.        Sticky(stickyContext,stickyXdata),
  2130.        Fighter(fighterContext,fighterXdata),
  2131.        User(userContext,userXdata)
  2132. {}
  2133.  
  2134.  
  2135.  
  2136. Boolean Ninja::is_fighter() 
  2137. {
  2138.   return True;
  2139. }
  2140.  
  2141.  
  2142.  
  2143. Boolean Ninja::is_sticky() 
  2144. {
  2145.   return True;
  2146. }
  2147.  
  2148.  
  2149.  
  2150. Boolean Ninja::is_user() 
  2151. {
  2152.   return True;
  2153. }
  2154.  
  2155.  
  2156.  
  2157. void Ninja::get_pixmap_mask(int dpyNum,Pixmap &pixmap,Pixmap &mask,Dir dir,int animNum)
  2158. {
  2159.   Fighter::get_pixmap_mask(dpyNum,pixmap,mask,dir,animNum);
  2160. }
  2161.  
  2162.  
  2163.  
  2164. void Ninja::get_size_offset_next(Size &size,Size &offset,Dir dirNext)
  2165. {
  2166.   Fighter::get_size_offset_next(size,offset,dirNext);
  2167. }
  2168.  
  2169.  
  2170.  
  2171. int Ninja::get_weapons_num()
  2172. {
  2173.   return User::get_weapons_num();
  2174. }
  2175.  
  2176.  
  2177.  
  2178. int Ninja::get_items_num()
  2179. {
  2180.   return User::get_items_num();
  2181. }
  2182.  
  2183.  
  2184.  
  2185. PhysicalP Ninja::get_weapon(int n)
  2186. {
  2187.   return User::get_weapon(n);
  2188. }
  2189.  
  2190.  
  2191.  
  2192. PhysicalP Ninja::get_item(int n)
  2193. {
  2194.   return User::get_item(n);
  2195. }
  2196.  
  2197.  
  2198.  
  2199.  
  2200. PhysicalP Ninja::get_weapon_current()
  2201. {
  2202.   return User::get_weapon_current();
  2203. }
  2204.  
  2205.  
  2206.  
  2207. PhysicalP Ninja::get_item_current()
  2208. {
  2209.   return User::get_item_current();
  2210. }
  2211.  
  2212.  
  2213.  
  2214. void Ninja::set_mapped_next(Boolean val)
  2215. {
  2216.  User::set_mapped_next(val);
  2217. }
  2218.  
  2219.  
  2220.  
  2221. void Ninja::act()
  2222. {
  2223.   Sticky::_act();
  2224.   Fighter::_act();
  2225.   Creature::act();
  2226.   User::_act();
  2227.   // NOTE: Creature::act() before User::act();
  2228. }
  2229.  
  2230.  
  2231.  
  2232. void Ninja::update()
  2233. {
  2234.   // Sticky::_update();
  2235.   Fighter::_update();
  2236.   // User::_update();
  2237.   Creature::update();
  2238. }
  2239.  
  2240.  
  2241.  
  2242. void Ninja::die()
  2243. {
  2244.   if (!get_quiet_death())
  2245.     stats.add_death(get_birth_time());
  2246.  
  2247.   // Sticky::_die();
  2248.   User::_die();
  2249.   // User::_die();
  2250.   Creature::die();
  2251. }
  2252.  
  2253.  
  2254.  
  2255. void Ninja::collide(PhysicalP other) 
  2256. {
  2257.   if (!Fighter::_collide(other) && !User::_collide(other))
  2258.     Creature::collide(other);
  2259. }
  2260.  
  2261.  
  2262.  
  2263. void Ninja::init_x(Xvars &xvars)
  2264. {
  2265.   Fighter::init_x(xvars);
  2266. }
  2267.  
  2268.  
  2269.  
  2270. Stats Ninja::stats;
  2271.  
  2272.  
  2273.  
  2274. Alien::Alien(WorldP w,LocatorP l,const Pos &rawPos) 
  2275.      : Creature(creatureContext,creatureXdata,w,l,rawPos),
  2276.        Sticky(stickyContext,stickyXdata)
  2277. {}
  2278.  
  2279.  
  2280.  
  2281. Boolean Alien::is_sticky()
  2282. {
  2283.   return True;
  2284. }
  2285.  
  2286.  
  2287.  
  2288. Boolean Alien::prickly()
  2289. {
  2290.   return True;
  2291. }
  2292.  
  2293.  
  2294.  
  2295. void Alien::collide(PhysicalP other)
  2296. {
  2297.   if (alive())
  2298.     other->corporeal_attack(this,ALIEN_DAMAGE);
  2299.  
  2300.   Sticky::collide(other);
  2301. }
  2302.  
  2303.  
  2304.  
  2305. void Alien::act()
  2306. {
  2307.   Sticky::act();
  2308. }
  2309.  
  2310.  
  2311.  
  2312. void Alien::die()
  2313. {
  2314.   if (!get_quiet_death())
  2315.     stats.add_death(get_birth_time());
  2316.  
  2317.   Sticky::die();
  2318. }
  2319.  
  2320.  
  2321.  
  2322. Stats Alien::stats;
  2323.  
  2324.  
  2325.  
  2326. ChopperBoy::ChopperBoy(WorldP w,LocatorP l,const Pos &rawPos) 
  2327.      : Creature(creatureContext,creatureXdata,w,l,rawPos),
  2328.        Flying(flyingContext,flyingXdata),
  2329.        User(userContext,userXdata)
  2330. {}
  2331.  
  2332.  
  2333.  
  2334. Boolean ChopperBoy::is_flying() 
  2335. {
  2336.   return True;
  2337. }
  2338.  
  2339.  
  2340.  
  2341. Boolean ChopperBoy::is_user() 
  2342. {
  2343.   return True;
  2344. }
  2345.  
  2346.  
  2347.  
  2348. int ChopperBoy::get_weapons_num()
  2349. {
  2350.   return User::get_weapons_num();
  2351. }
  2352.  
  2353.  
  2354.  
  2355. int ChopperBoy::get_items_num()
  2356. {
  2357.   return User::get_items_num();
  2358. }
  2359.  
  2360.  
  2361.  
  2362. PhysicalP ChopperBoy::get_weapon(int n)
  2363. {
  2364.   return User::get_weapon(n);
  2365. }
  2366.  
  2367.  
  2368.  
  2369. PhysicalP ChopperBoy::get_item(int n)
  2370. {
  2371.   return User::get_item(n);
  2372. }
  2373.  
  2374.  
  2375.  
  2376.  
  2377. PhysicalP ChopperBoy::get_weapon_current()
  2378. {
  2379.   return User::get_weapon_current();
  2380. }
  2381.  
  2382.  
  2383.  
  2384. PhysicalP ChopperBoy::get_item_current()
  2385. {
  2386.   return User::get_item_current();
  2387. }
  2388.  
  2389.  
  2390.  
  2391. void ChopperBoy::set_mapped_next(Boolean val)
  2392. {
  2393.  User::set_mapped_next(val);
  2394. }
  2395.  
  2396.  
  2397.  
  2398. void ChopperBoy::act()
  2399. {
  2400.   Flying::_act();
  2401.   Creature::act();
  2402.   User::_act();
  2403.   // NOTE: Creature::act() before User::act();
  2404. }
  2405.  
  2406.  
  2407.  
  2408. void ChopperBoy::update()
  2409. {
  2410.   Creature::update();
  2411. }
  2412.  
  2413.  
  2414.  
  2415. void ChopperBoy::die()
  2416. {
  2417.   if (!get_quiet_death())
  2418.     stats.add_death(get_birth_time());
  2419.  
  2420.   User::_die();
  2421.   Creature::die();
  2422. }
  2423.  
  2424.  
  2425.  
  2426. void ChopperBoy::collide(PhysicalP other) 
  2427. {
  2428.   if (!User::_collide(other))
  2429.     Creature::collide(other);
  2430. }
  2431.  
  2432.  
  2433.  
  2434. Stats ChopperBoy::stats;
  2435.  
  2436.  
  2437.  
  2438. Lemming::Lemming(WorldP w,LocatorP l,const Pos &rawPos)
  2439. : Creature(creatureContext,creatureXdata,w,l,rawPos),
  2440.   Grounded(groundedContext,groundedXdata),
  2441.   Suicide(suicideContext,suicideXdata)
  2442. {}
  2443.  
  2444.  
  2445.  
  2446. Boolean Lemming::is_suicide()
  2447. {
  2448.   return True;
  2449. }
  2450.  
  2451.  
  2452.  
  2453. void Lemming::act()
  2454. {
  2455.   Grounded::_act();
  2456.   Suicide::_act();
  2457.   Creature::act();
  2458. }
  2459.  
  2460.  
  2461.  
  2462. void Lemming::die()
  2463. {
  2464.   if (!get_quiet_death())
  2465.     stats.add_death(get_birth_time());
  2466.   
  2467.   Grounded::die();
  2468. }
  2469.  
  2470.  
  2471.  
  2472. Stats Lemming::stats;
  2473.  
  2474.  
  2475.  
  2476. FireDemon::FireDemon(WorldP w,LocatorP l,const Pos &rawPos) 
  2477.      : Creature(creatureContext,creatureXdata,w,l,rawPos),
  2478.        Flying(flyingContext,flyingXdata),
  2479.        BuiltIn(builtInContext,builtInXdata)
  2480. {
  2481.   swapResistance = FIRE_DEMON_SWAP_RESISTANCE;
  2482. }
  2483.  
  2484.  
  2485.  
  2486. Boolean FireDemon::is_flying() 
  2487. {
  2488.   return True;
  2489. }
  2490.  
  2491.  
  2492.  
  2493. Boolean FireDemon::is_built_in()
  2494. {
  2495.   return True;
  2496. }
  2497.  
  2498.  
  2499.  
  2500. Boolean FireDemon::ready()
  2501. {
  2502.   return BuiltIn::ready();
  2503. }
  2504.  
  2505.  
  2506.  
  2507. void FireDemon::heat_attack(PhysicalP,int,Boolean)
  2508. {}
  2509.  
  2510.  
  2511.  
  2512. Boolean FireDemon::swap_protect()
  2513. {
  2514.   if (swapResistance > 0)
  2515.     {
  2516.       swapResistance--;
  2517.       return True;
  2518.     }
  2519.   return False;
  2520. }
  2521.  
  2522.  
  2523.  
  2524. Boolean FireDemon::frog_protect()
  2525. {
  2526.   return True;
  2527. }
  2528.  
  2529.  
  2530.  
  2531. Size FireDemon::get_shot_size(Dir)
  2532. {
  2533.   return Fireball::get_size();
  2534. }
  2535.  
  2536.  
  2537.  
  2538. PhysicalP FireDemon::create_shot(const Pos &pos,Dir dir)
  2539. {
  2540.   PhysicalP shot = 
  2541.     new Fireball(get_world(),get_locator(),pos,get_id(),dir,
  2542.          FIRE_DEMON_FIREBALL_HEAT,FIRE_DEMON_FIREBALL_TIME);
  2543.   assert(shot);
  2544.   return shot;
  2545. }
  2546.  
  2547.  
  2548.  
  2549. void FireDemon::act()
  2550. {
  2551.   const Area &area = get_area();
  2552.   Pos pos;
  2553.   Size size;
  2554.   area.get_rect(pos,size);
  2555.   LocatorP locator = get_locator();
  2556.  
  2557.   // Generate fire.
  2558.   for (int n = 0; n < FIRE_DEMON_FIRE; n++)
  2559.     {
  2560.       Pos firePos(pos.x + Utils::choose(size.width),
  2561.           pos.y + Utils::choose((int)(.8 * size.height))); 
  2562.       
  2563.       PhysicalP fire = new Fire(get_world(),locator,firePos,False);
  2564.       locator->add(fire);
  2565.     }
  2566.  
  2567.   Flying::_act();
  2568.   BuiltIn::_act();
  2569.   Creature::act();
  2570. }
  2571.  
  2572.  
  2573.  
  2574. void FireDemon::collide(PhysicalP other)
  2575. {
  2576.   if (alive() && !other->is_shot())
  2577.     other->heat_attack(this,FIRE_DEMON_HEAT);
  2578.   
  2579.   Flying::collide(other);
  2580. }
  2581.